package org.miniframework.aop;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.miniframework.aop.aspect.AspectInfo1;
import org.miniframework.util.ValidationUtil;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * AOP 1.0(不支持表达式)
 */
@Deprecated
public class AspectListExecutor1 implements MethodInterceptor {
    // 被代理的类
    private Class<?> targetClass;
    private List<AspectInfo1> aspectInfo1List;

    public AspectListExecutor1(Class<?> targetClass, List<AspectInfo1> aspectInfo1List){
        this.targetClass = targetClass;
        this.aspectInfo1List = sortAspectInfoList(aspectInfo1List);
    }

    /**
     * 根据 order 进行排序，值越小越先执行
     * @param aspectInfo1List
     * @return
     */
    private List<AspectInfo1> sortAspectInfoList(List<AspectInfo1> aspectInfo1List) {
        Collections.sort(aspectInfo1List, new Comparator<AspectInfo1>() {
            @Override
            public int compare(AspectInfo1 o1, AspectInfo1 o2) {
                return o1.getOrderIndex() - o2.getOrderIndex();
            }
        });
        return aspectInfo1List;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object returnValue = null;
        if (ValidationUtil.isEmpty(aspectInfo1List)){
            return returnValue;
        }
        // 1.按照 order 顺序升序执行完所有的 Aspect 的 before 方法
        invokeBeforeAdvices(method,args);
        try {
            // 2.执行被代理类的方法
            returnValue = methodProxy.invokeSuper(proxy,args);
            // 3.如果被代理方法正常返回，则按照order顺序降序执行完所有的Aspect的afterReturning方法
            returnValue = invokeAfterReturningAdvices(method,args,returnValue);
        }catch (Exception e){
            // 4.如果被代理方法抛出异常，则按照order顺序降序执行完所有的Aspect的afterThrowing方法
            invokeAfterThrowingAdvices(method,args,e);
        }
        return returnValue;
    }

    // 4.如果被代理方法抛出异常，则按照order顺序降序执行完所有的Aspect的afterThrowing方法
    private void invokeAfterThrowingAdvices(Method method, Object[] args, Exception e) throws Throwable {
        for (int i = aspectInfo1List.size() - 1; i >= 0; i--) {
            aspectInfo1List.get(i).getDefaultAspect().afterThrowing(targetClass,method,args,e);
        }
    }

    // 3.如果被代理方法正常返回，则按照order顺序降序执行完所有的Aspect的afterReturning方法
    private Object invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {
        Object result = null;
        for (int i = aspectInfo1List.size() - 1; i >= 0; i--) {
            result = aspectInfo1List.get(i).getDefaultAspect().afterReturning(targetClass,method,args,returnValue);
        }
        return result;
    }

    // 1.按照 order 顺序升序执行完所有的 Aspect 的 before 方法
    private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
        for (AspectInfo1 aspectInfo1 : aspectInfo1List){
            aspectInfo1.getDefaultAspect().before(targetClass,method,args);
        }
    }
}
